package it.koutifaris.travianmap.tile.tilemap;

import static org.mockito.AdditionalMatchers.geq;
import static org.mockito.AdditionalMatchers.lt;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import it.koutifaris.travianmap.dal.RevisionService.Revision;
import it.koutifaris.travianmap.model.Village;
import it.koutifaris.travianmap.tile.Tile;
import it.koutifaris.travianmap.tile.TileBounds;
import it.koutifaris.travianmap.tile.TileLoader;
import it.koutifaris.travianmap.tile.TileMapLoader;
import it.koutifaris.travianmap.tile.bounds.DefaultTileBounds;

import java.util.ArrayList;

public class MapMockupFactory {

	private final MapVillageMockupFactory villageMockupFactory = new MapVillageMockupFactory();

	public TileMapLoader mapLoaderMockup() {
		TileLoader tileLoaderMockup = tileLoaderMockup();
		return mapLoaderMockup(tileLoaderMockup);
	}

	public TileMapLoader mapLoaderMockup(TileLoader tileLoader) {
		TileMapLoader mapLoader = mock(TileMapLoader.class);

		when(mapLoader.getLoaderFor((Revision) any())).thenReturn(tileLoader);

		return mapLoader;
	}

	public TileLoader tileLoaderMockup() {
		TileLoader tileLoader = mock(TileLoader.class);

		setupTestTiles(tileLoader);

		return tileLoader;
	}

	private void setupTestTiles(TileLoader tileLoader) {
		Tile northWestTileMockup = northWestTileMockup();
		when(northWestCondition(tileLoader)).thenReturn(northWestTileMockup);

		Tile northEastTileMockup = northEastTileMockup();
		when(nortEastCondition(tileLoader)).thenReturn(northEastTileMockup);

		Tile southEastTileMockup = southEastTileMockup();
		when(southEastCondition(tileLoader)).thenReturn(southEastTileMockup);

		Tile southWestTileMockup = southWestTileMockup();
		when(southWestCondition(tileLoader)).thenReturn(southWestTileMockup);
	}

	private Tile northWestCondition(TileLoader tileLoader) {
		return tileLoader.loadTileAt(lt(0), lt(0));
	}

	private Tile nortEastCondition(TileLoader tileLoader) {
		return tileLoader.loadTileAt(geq(0), lt(0));
	}

	private Tile southEastCondition(TileLoader tileLoader) {
		return tileLoader.loadTileAt(geq(0), geq(0));
	}

	private Tile southWestCondition(TileLoader tileLoader) {
		return tileLoader.loadTileAt(lt(0), geq(0));
	}

	private Tile northWestTileMockup() {
		return tileMockup(getVillageMockupFactory().northWestVillage());
	}

	private Tile northEastTileMockup() {
		return tileMockup(getVillageMockupFactory().northEastVillage());
	}

	private Tile southEastTileMockup() {
		return tileMockup(getVillageMockupFactory().southEastVillage());
	}

	private Tile southWestTileMockup() {
		return tileMockup(getVillageMockupFactory().southWestVillage());
	}

	private MapVillageMockupFactory getVillageMockupFactory() {
		return villageMockupFactory;
	}

	private Tile tileMockup(Village village) {
		Tile tile = mock(Tile.class);

		when(tile.getNumberOfVillages()).thenReturn(1);
		ArrayList<Village> villages = new ArrayList<Village>(1);
		villages.add(village);
		when(tile.getVillages()).thenReturn(villages);

		TileBounds tileBoundsMockup = tileBoundsMockup(village);
		when(tile.getBounds()).thenReturn(tileBoundsMockup);

		return tile;
	}

	private TileBounds tileBoundsMockup(Village village) {
		TileBounds bounds = DefaultTileBounds.builder()
				.setOrigin(getTileOriginFromVillage(village.getX()), getTileOriginFromVillage(village.getY()))
				.withSize(3, 3)
				.build();

		return bounds;
	}

	private int getTileOriginFromVillage(int coord) {
		return (coord >= 0) ? 0 : -3;
	}
}
